﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
using NetCDFDotnet;
using OSGeo.GDAL;

namespace GeoFly
{

    
	/// <summary>
	/// 栅格图层信息和数据
	/// </summary>
	public class GridLayer
	{
		/// <summary>
		/// 默认构造函数，只创建对象，不生成任何数据
		/// </summary>
		public GridLayer()
		{

		}
		/// <summary>
		/// 生成指定行列数据栅格数据，所有数据都初始化为无数据值
		/// </summary>
		/// <param name="rowCount">行数</param>
		/// <param name="colCount">列数</param>
		/// <param name="nodata_value">无数据值</param>
		public GridLayer(int rowCount, int colCount, double nodata_value)
		{
			this.nodata = nodata_value;
			//this.Values = new double[rowCount, colCount];
//            for (int i = 0; i < rowCount; i++)
//            {
//                for (int j = 0; j < colCount; j++)
//                {
//                    Values[i, j] = nodata_value;
//                }
//            }
		}
		/// <summary>
		/// 复制所有属性和数据的函数
		/// </summary>
		/// <returns></returns>
		public GridLayer DeepCopy()
		{
			GridLayer layer = new GridLayer();
			layer.DownLeft_X = this.DownLeft_X;
			layer.DownLeft_Y = this.DownLeft_Y;
			layer.resolution = this.resolution;
			layer.nodata = this.nodata;
			layer.Values = new double[rowCount, colCount];
			for (int i = 0; i < rowCount; i++) {
				for (int j = 0; j < colCount; j++) {
					layer.Values[i, j] = this.Values[i, j];
				}
			}

			return layer;
		}
        
		/// <summary>
		/// 复制所有属性并初始化结构，但不复制数据
		/// </summary>
		/// <returns></returns>
		public GridLayer AttributesCopy()
		{
			GridLayer layer = new GridLayer(this.rowCount, this.colCount, this.nodata);           
			layer.resolution = this.resolution;
			layer.DownLeft_X = this.DownLeft_X;
			layer.DownLeft_Y = this.DownLeft_Y;
			return layer;
		}

		/// <summary>
		/// 复制所有属性并初始化结构，但不复制数据
		/// </summary>
		/// <returns></returns>
		public GridLayer AttributesCopy(double initialValue)
		{
			GridLayer layer = new GridLayer(this.rowCount, this.colCount, initialValue);
			layer.resolution = this.resolution;
			layer.DownLeft_X = this.DownLeft_X;
			layer.DownLeft_Y = this.DownLeft_Y;
			return layer;
		}

		/// <summary>
		/// 根据行列号取得当前栅格中心的位置坐标
		/// </summary>
		/// <param name="currow">当前栅格行号</param>
		/// <param name="curcol">当前栅格列号</param>
		/// <returns>返回坐标点</returns>
		public LPoint CellPosition(int currow, int curcol)
		{
			if (currow < 0 || curcol < 0) {
				return null;
			}

			double dx = Extent.xmin + (2 * curcol + 1) * resolution / 2.0;
			double dy = Extent.ymax - (2 * currow + 1) * resolution / 2.0;
			return new LPoint(dx, dy);
		}
        

		/// <summary>
		/// 求最大值和最小值
		/// </summary>
		public void CalMaxMinValue()
		{
            
			double max = -99999;
			double min = 99999;
			for (int i = 0; i < this.rowCount; i++) {
				for (int j = 0; j < this.colCount; j++) {
					if (Values[i, j] < -9990)  //如果无数据就绕过，进入下一趟循环
                        continue;
					if (max < Values[i, j])
						max = Values[i, j];
					if (min > Values[i, j])
						min = Values[i, j];
				}
			}
			this.MaxValue = max;
			this.MinValue = min;
		}
		//取得pGridValue中所有的数值,即计算绝对直方图
		public SortedList<double, int> GetAllValue(List<string> saValue)
		{
			//存放直方图的结构，double型的键指象元的数值，int指取该数值的象元的个数
			SortedList<double, int> hist = new SortedList<double, int>();
			for (int i = 0; i < this.rowCount; i++) {
				for (int j = 0; j < this.colCount; j++) {
					double value = this.Values[i, j];
					if (hist.ContainsKey(value)) //如果包含该数值，则在原有的个数上加1
                        hist[value] += 1;
					else
						hist[value] = 1;    //如果不包含该数值，则设为1(即为第1个)
				}
			}
			this.AbsoluteHistgram = hist;
			return hist;
		}

		//取得pGridValue中所有数值所占的比例，即比例直方图
		public SortedList<double, double> GetAllPercentage()
		{
			int AllPixels = this.rowCount * this.colCount;
			//KeyValuePair<double,int> pair;
			foreach (KeyValuePair<double, int> pair in this.AbsoluteHistgram) {
				this.PercentageHistgram[pair.Key] = (double)pair.Value / AllPixels;
			}
			return this.PercentageHistgram;
		}
		/// <summary>
		/// 读取SRTM HGT文件的DEM
		/// </summary>
		/// <param name="filename"></param>
		public void ReadHGT(string filename)
		{
			this.FileName = filename;
			FileStream stream = new FileStream(filename, FileMode.Open);
			BinaryReader br = new BinaryReader(stream);
			this.Values = new double[1201, 1201];
			for (int row = 0; row < 1201; row++) {
				for (int col = 0; col < 1201; col++) {
					byte[] bytes = br.ReadBytes(2);
					int v = bytes[0] * 256 + bytes[1];
					if (v > 9999 || v < -9999)
						v = -10;
					this.Values[row, col] = v;
				}
			}
		}

		/// <summary>
		/// 取得pGridValue中小于dThreshold的象素个数所占比例(0.0～1.0)
		/// </summary>
		/// <param name="dThreshold">门限值</param>
		/// <returns></returns>
		double GetPercentByThreshold(SortedList<double, double> PercentHist)
		{
			double sum = 0.0;
			foreach (KeyValuePair<double, double> pair in PercentHist) {
				sum += pair.Value;
			}
			return sum;
		}
		/// <summary>
		///栅格数据文件读入(ASCII格式)
		///
		///可读入下列格式（并继续补充）
		///*-------------1: ArcInfo格式的ASC文件--------------*/
		///文件头
		///		ncols         1048
		///		nrows         1062
		///		xllcorner     666198
		///		yllcorner     3724676.5
		///		cellsize      60
		///		NODATA_value  -9999
		///第七行开始为数据
		///*---------------------------------------------------*/
		///2: Envi格式的ASC文件，即Envi转出的Asc格式的文本文件
		///文件头
		///		;
		///		; ENVI ASCII Output of file: I:\两河口\img\tm60m [Mon Apr 26 19:14:32 2004]
		///		; File Dimensions: 1048 samples x 1062 lines x 7 bands
		///		; Line Format    : (1048i4)
		///		;
		///第6行开始为数据
		///*---------------------------------------------------*/
		///3: Envi格式的带地理坐标的Asc格式的文本文件
		///*---------------------------------------------------*/
		/// </summary>
		/// <param name="strFile"></param>
		/// <param name="gridlayer"></param>
		/// <returns></returns>
		public bool ReadASC(string strFile)			//常规方法读取栅格图层文件
		{
			this.FileName = strFile;
			List<string> saIn = new List<string>();
			saIn = this.FileRead(strFile);

			//判断文件格式
			Asc_Grid_File_Format AscFormat = Asc_Grid_File_Format.NOT_DEFINED_ASC_FORMAT;

			//根据第0行文本中的最左边字符判断
			string[] s = saIn[0].Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);

			if (s[0][0] == ';')
				AscFormat = Asc_Grid_File_Format.ENVI_STD_ASC_FORMAT;
			else if (s[0] == "ncols") {
				//获取第5行文本
				string[] str = saIn[5].Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
				if (str[0].ToLower() == "nodata_value")
					AscFormat = Asc_Grid_File_Format.ARCINFO_ASC_FORMAT;
				else
					AscFormat = Asc_Grid_File_Format.ENVI_GRID_ASC_FORMAT;
			}
			int begline = -1;

			if (AscFormat == Asc_Grid_File_Format.ARCINFO_ASC_FORMAT) {
				this.ParseArcInfoAscHeader(saIn);
				begline = 6;
			} else if (AscFormat == Asc_Grid_File_Format.ENVI_STD_ASC_FORMAT) {
				this.ParseEnviAscHeader(saIn);
				begline = 5;
			} else if (AscFormat == Asc_Grid_File_Format.ENVI_GRID_ASC_FORMAT) {
				this.ParseEnviGridHeader(saIn);
				begline = 5;
			} else {
				this.rCount = saIn.Count;
				this.cCount = saIn[0].Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries).Length;
				MessageBox.Show("可能是不带文件头的AscII码数据文件，下面尝试读入");
				begline = 0;
			}
			//开始处理数据
			this.ParseAscData(saIn, Values, begline);
            
			return true;
		}
		/// <summary>
		/// 将Asc码组成的有关数据字符串(saIn)解释成浮点数矩阵存放在Values数组中
		/// 从saIn的第begline行开始
		/// </summary>
		/// <param name="saIn"></param>
		/// <param name="Values"></param>
		/// <param name="begline"></param>
		private void ParseAscData(List<string> saIn, double[,] Values, int begline)
		{
			ProgressBar bar = new ProgressBar();
			bar.Show();
			bar.Text = "正在转化数据";
			this.Values = new double[rCount, cCount];
			//读入Grid文件的数据	    
			for (int i = 0; i < this.rCount; i++) {
				if (saIn[begline] == "") {
					MessageBox.Show("数据中有空行，请删除Grid数据文件中的空行再运行该程序");
					return;
				}
				//从第六行开始为数据
				string[] strbuffer = saIn[begline + i].Split(new char[] {
					' ',
					'\t'
				}, StringSplitOptions.RemoveEmptyEntries);

				if (strbuffer.Length != this.cCount) {
					throw new Exception("数据列数和头文件不符：头文件中" + colCount.ToString() + "列" + "实际得到" + strbuffer.Length.ToString() + "列。");

				}
				for (int j = 0; j < this.cCount; j++) {
					this.Values[i, j] = Convert.ToDouble(strbuffer[j]);
				}
				int progress = (int)(i * 100.0 / this.rCount);
				bar.progressBar1.Value = progress;
			}
			//this.bReady = true;
			bar.Close();
		}
		/// <summary>
		/// 处理ArcInfo的asc码格式的头文件
		/// </summary>
		/// <param name="saIn"></param>
		private void ParseArcInfoAscHeader(List<string> saIn)
		{
			//获取总行数
			string[] strs;
			strs = saIn[0].Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
			this.cCount = Convert.ToInt32(strs[1]);

			//获取总列数
			strs = saIn[1].Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
			this.rCount = Convert.ToInt32(strs[1]);

			//获取xllcorner
			strs = saIn[2].Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
			this.DownLeft_X = Convert.ToDouble(strs[1]);

			//获取yllcorner
			strs = saIn[3].Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
			this.DownLeft_Y = Convert.ToDouble(strs[1]);

			//获取分辩率
			strs = saIn[4].Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
			this.resolution = Convert.ToDouble(strs[1]);
			this.nodata = -9999;
		}
		/// <summary>
		/// 处理Envi AscII码格式的头文件
		/// </summary>
		/// <param name="saIn"></param>
		private void ParseEnviAscHeader(List<string> saIn)
		{
			//在行号为2的行(即第3行)中获取字符串列表
			string[] strs = saIn[2].Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
			this.cCount = Convert.ToInt32(strs[3]);
			this.rCount = Convert.ToInt32(strs[6]);
			this.resolution = -9999;
		}
		/// <summary>
		/// 处理Envi中输出的AscII码格式头文件,这个文件头与AscInfo近似，只是少了nodatavalue行
		/// </summary>
		/// <param name="saIn"></param>
		private void ParseEnviGridHeader(List<string> saIn)
		{
			this.ParseArcInfoAscHeader(saIn);
		}
		private List<string> FileRead(string FileName)
		{
			//检查文件
			if (!File.Exists(FileName)) {
				MessageBox.Show("文件" + FileName + "不存在！");
				return null;
			}
			ProgressBar bar = new ProgressBar();
			bar.Enabled = true;
			bar.Show();
			bar.Text = "正在读取数据";
			List<string> slist = new List<string>();
			StreamReader sr = new StreamReader(FileName);
			while (!sr.EndOfStream) {
				string s = sr.ReadLine();
				if (s != "")
					slist.Add(s);
			}
			sr.Close();
			bar.Close();
			return slist;
		}
        
		public void SaveToNetCDF(string FileName)
		{
			if (this.resolution > 0) {
				int ncid = -1;
				NC_LowAPI.nc_create(FileName, 1, ref ncid);
				int latId = -1;
				int lonId = -1;
				NC_LowAPI.nc_def_dim(ncid, "lat", this.rowCount, ref latId);
				NC_LowAPI.nc_def_dim(ncid, "lon", this.colCount, ref lonId);
				int varId = -1;
				int latVarId = -1;
				int lonVarId = -1;
				NC_LowAPI.nc_def_var(ncid, "lat", NC_Type.NC_FLOAT, 1, new int[]{ latId }, ref latVarId);
				NC_LowAPI.nc_def_var(ncid, "lon", NC_Type.NC_FLOAT, 1, new int[]{ lonId }, ref lonVarId);
        	                     
				NC_LowAPI.nc_def_var(ncid, "data", NC_Type.NC_FLOAT, 2, new int[] {
					latId,
					lonId
				}, ref varId);
				NC_LowAPI.nc_put_att_string(ncid, varId, "history", 50, "Created at " + DateTime.Now + " by GridDataViewer.");
				NC_LowAPI.nc_enddef(ncid);
				float[] lats = new float[rowCount];
				float[] lons = new float[colCount];
				for (int i = 0; i < this.rowCount; i++) {
					lats[i] = (float)(Extent.ymin + (rowCount - i - 1) * resolution);
				}
				for (int i = 0; i < this.colCount; i++) {
					lons[i] = (float)(Extent.xmin + i * resolution);
				}
        	
				NC_LowAPI.nc_put_var_float(ncid, latId, lats);
				NC_LowAPI.nc_put_var_float(ncid, lonId, lons);
				float[] values = new float[this.rowCount * this.colCount];
				for (int row = 0; row < this.rowCount; row++) {
					for (int col = 0; col < this.colCount; col++) {
						values[row * colCount + col] = (float)this.Values[row, col];
					}
				}
				int res = NC_LowAPI.nc_put_var_float(ncid, varId, values);
        	
				NC_LowAPI.nc_close(ncid);
			} else {
				int ncid = -1;
				NC_LowAPI.nc_create(FileName, 1, ref ncid);
				int latId = -1;
				int lonId = -1;
				NC_LowAPI.nc_def_dim(ncid, "Y", this.rowCount, ref latId);
				NC_LowAPI.nc_def_dim(ncid, "X", this.colCount, ref lonId);
				int varId = -1;
				int latVarId = -1;
				int lonVarId = -1;
				NC_LowAPI.nc_def_var(ncid, "Y", NC_Type.NC_FLOAT, 1, new int[]{ latId }, ref latVarId);
				NC_LowAPI.nc_def_var(ncid, "X", NC_Type.NC_FLOAT, 1, new int[]{ lonId }, ref lonVarId);        	                     
				NC_LowAPI.nc_def_var(ncid, "data", NC_Type.NC_FLOAT, 2, new int[] {
					latId,
					lonId
				}, ref varId);
				NC_LowAPI.nc_put_att_string(ncid, varId, "history", 50, "Created at " + DateTime.Now + " by GridDataViewer.");
				NC_LowAPI.nc_enddef(ncid);
				float[] lats = new float[rowCount];
				float[] lons = new float[colCount];
				for (int i = 0; i < this.rowCount; i++) {
					lats[i] = (float)(i);
				}
				for (int i = 0; i < this.colCount; i++) {
					lons[i] = (float)(i);
				}
        	
				NC_LowAPI.nc_put_var_float(ncid, latId, lats);
				NC_LowAPI.nc_put_var_float(ncid, lonId, lons);
				float[] values = new float[this.rowCount * this.colCount];
				for (int row = 0; row < this.rowCount; row++) {
					for (int col = 0; col < this.colCount; col++) {
						values[row * colCount + col] = (float)this.Values[rowCount - 1 - row, col];
					}
				}
				int res = NC_LowAPI.nc_put_var_float(ncid, varId, values);
        	    
				NC_LowAPI.nc_close(ncid);
			}
		}
		
		public void SaveToGeoTiff(string FileName)
		{
			Gdal.AllRegister();
			Driver driver = Gdal.GetDriverByName("GTiff");
			
			string[] options = new string[]{ "TILED=YES", "COMPRESS=PACKBITS" };
			Dataset ds = driver.Create(FileName, this.colCount, this.rowCount, 1, DataType.GDT_Float32, options);
			double[] geotrans = new double[6];
			geotrans[0] = this.DownLeft_X;
			geotrans[1] = this.resolution;
			geotrans[2] = 0;
			geotrans[3] = this.DownLeft_Y - (this.rowCount - 1) * resolution;
			geotrans[4] = 0;
			geotrans[5] = this.resolution;
			ds.SetGeoTransform(geotrans);
			float[] values = new float[this.rowCount * this.colCount];
			for (int row = 0; row < this.rowCount; row++) {
				for (int col = 0; col < this.colCount; col++) {
					values[row * this.colCount + col] = (float)this.Values[row, col];
				}
			}
			Band band = ds.GetRasterBand(1);
			band.SetDescription("Dataset");
			band.WriteRaster(0, 0, this.colCount, this.rowCount, values, colCount, rowCount, 0, 0);
		}

		
		public bool WriteASC(string FileName)
		{
			ProgressBar bar = new ProgressBar();
			bar.Show();
			bar.Text = "正在写文件头部分";
			StreamWriter sw = new StreamWriter(FileName);
			//写文件头
			sw.WriteLine("ncols\t" + colCount);
			sw.WriteLine("nrows\t" + rowCount);
			sw.WriteLine("xllcorner\t" + Extent.xmin);
			sw.WriteLine("yllcorner\t" + Extent.ymin);
			sw.WriteLine("cellsize\t" + resolution);
			sw.WriteLine("NODATA_value\t" + nodata);
			//写文件头结束

            
			bar.Text = "正在保存数据体" + FileName;
			//下面写数据体
			for (int i = 0; i < rowCount; i++) {
				for (int j = 0; j < colCount; j++) {
					//if (Values[i, j] > 0)
					//    throw new Exception("");
					sw.Write(Values[i, j].ToString("0.0000") + "\t");
					int progress = (int)(i * 100.0 / this.rowCount);
					bar.progressBar1.Value = progress;
				}
				sw.WriteLine();
			}
			bar.Close();
			sw.Close();
			return true;

		}
		/// <summary>
		/// 写入部分数据
		/// </summary>
		/// <param name="FileName"></param>
		/// <returns></returns>
		public void WriteASC(string FileName, int beginrow, int endrow, int begincol, int endcol)
		{
			this.FileName = FileName;
			ProgressBar bar = new ProgressBar();
			bar.Show();
			bar.Text = "正在写文件头部分";
			StreamWriter sw = new StreamWriter(FileName);
			//写文件头
			int col = endcol - begincol + 1;
			int row = endrow - beginrow + 1;

			sw.WriteLine("ncols\t" + col);//写列数
			sw.WriteLine("nrows\t" + row);//写行数
			sw.WriteLine("xllcorner\t" + Extent.xmin);//写范围的最小值
			sw.WriteLine("yllcorner\t" + Extent.ymin);//写范围的最小值
			sw.WriteLine("cellsize\t" + resolution);//写分辨率
			sw.WriteLine("NODATA_value\t" + nodata);

			//写文件头结束


			bar.Text = "正在保存数据体";
			//下面写数据体
			for (int i = beginrow; i <= endrow; i++) {
				for (int j = begincol; j <= endcol; j++) {
					sw.Write(Math.Round(Values[i, j], 4).ToString() + "\t");
					int progress = (int)(i * 100.0 / this.rowCount);
					bar.progressBar1.Value = progress;
				}
				sw.WriteLine();
			}
			bar.Close();
			sw.Close();
		}
		//        /// <summary>
		//        /// 读取NetCDF中的变量，只读取二维数据
		//        /// </summary>
		//        /// <param name="filename"></param>
		//        public void ReadNetCDF(string filename)
		//        {
		//        	int ncid=-1;
		//        	LowAPI.nc_open(filename, 0, ref ncid);
		//        	StringBuilder sb=new StringBuilder();
		//        	int rows=-1;
		//        	int cols=-1;
		//        	LowAPI.nc_inq_dim(ncid,0,sb,ref rows);
		//        	LowAPI.nc_inq_dim(ncid,1,sb,ref cols);
		//        	Console.WriteLine("NetCDF rows and cols:"+rows+" "+cols);
		//
		//        	if(rows==-1 || cols==-1)
		//        	{
		//        		Console.WriteLine("出现异常，行列号均为-1");
		//        		return;
		//        	}
		//        	this.rCount=rows;
		//        	this.cCount=cols;
		//        	this.Values=new double[rows,cols];
		//        	NC_Type type=NC_Type.NC_BYTE;
		//        	LowAPI.nc_inq_vartype(ncid,0,ref type);
		//        	if(type==NC_Type.NC_FLOAT)
		//        	{
		//        		//默认取第0个变量，且假定其维数为默认的0，1维
		//        		for(int row=0;row<rows;row++)
		//        		{
		//        			int[] start=new int[]{row,0};
		//        			int[] count=new int[]{1,cols};
		//        			float[] temp=new float[cols];
		//        			LowAPI.nc_get_vara_float(ncid,0,start,count,temp);
		//        			for(int col=0;col<cols;col++)
		//        			{
		//        				this.Values[row,col]=temp[col];
		//        			}
		//        		}
		//        	}
		//        	else if(type==NC_Type.NC_DOUBLE)
		//        	{
		//        		//默认取第0个变量，且假定其维数为默认的0，1维
		//        		for(int row=0;row<rows;row++)
		//        		{
		//        			int[] start=new int[]{row,0};
		//        			int[] count=new int[]{1,cols};
		//        			double[] temp=new double[cols];
		//        			LowAPI.nc_get_vara_double(ncid,0,start,count,temp);
		//        			for(int col=0;col<cols;col++)
		//        			{
		//        				this.Values[row,col]=temp[col];
		//        			}
		//        		}
		//        	}
		//        	else if(type==NC_Type.NC_INT)
		//        	{
		//        		//默认取第0个变量，且假定其维数为默认的0，1维
		//        		for(int row=0;row<rows;row++)
		//        		{
		//        			int[] start=new int[]{row,0};
		//        			int[] count=new int[]{1,cols};
		//        			int[] temp=new int[cols];
		//        			LowAPI.nc_get_vara_int(ncid,0,start,count,temp);
		//        			for(int col=0;col<cols;col++)
		//        			{
		//        				this.Values[row,col]=temp[col];
		//        			}
		//        		}
		//        	}
		//        	else
		//        	{
		//        		Console.WriteLine("数据类型不是整型、单精度或浮点型，现在不支持");
		//        	}
		//        }
		/// <summary>
		/// 生成标准彩色图像
		/// </summary>
		/// <returns></returns>
		public Bitmap CreateBitmap5()
		{
			Bitmap bitmap = MatrixFuncs.BitmapFromMatrix5(this.Values);
			this.theBitmap = bitmap;
			return bitmap;
		}
		/// <summary>
		/// 生成标准彩色图像
		/// </summary>
		/// <returns></returns>
		public Bitmap CreateBitmap6()
		{
			this.CalMaxMinValue();
			Bitmap bitmap = MatrixFuncs.BitmapFromMatrix_Pallete(this.Values, this.MaxValue, this.MinValue, 15);
			//.BitmapFromMatrix6(this.Values, this.MaxValue, this.MinValue);
			this.theBitmap = bitmap;
			return bitmap;
		}
        
		public Bitmap colorbarImage = null;
        
		public static string[] ToStr(double v)
		{
			if (Math.Abs(v) < 1e-20)
				return new string[]{ "0" };
			if (Math.Abs(v) < 0.001 || Math.Abs(v) > 10000) {
				int exp = (int)Math.Log10(Math.Abs(v));
				double temp = v / Math.Pow(10, exp);
				return new string[]{ temp.ToString("0.000"), exp.ToString() };
			}
			if (Math.Abs(v) < 1)
				return new string[]{ v.ToString("0.0000") };
			if (Math.Abs(v) < 100)
				return new string[]{ v.ToString("0.00") };
			return new string[]{ Math.Round(v, 0).ToString() };
        	
		}
		public void DrawColorbar(Graphics g, int x, int y)
		{
			
			if (colorbarImage == null) {
				colorbarImage = new Bitmap(100, 600);
				Graphics bg = Graphics.FromImage(colorbarImage);
				bg.InterpolationMode= System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
				double max = this.MaxValue;
				double min = this.MinValue;
				
				int count = 15;
				double scope = max - min;
				double step = scope / count;
				Color[] colors = new Color[count];
				for (int i = 0; i < count; i++) {
					colors[i] = MatrixFuncs.ToColor6(min, max, step * i + min);
				}
				int height = 30;
				for (int i = 0; i < count; i++) {
					SolidBrush brush = new SolidBrush(colors[i]);
					bg.FillRectangle(brush, 0, height * i+10, 30, height);	
					bg.DrawRectangle(Pens.Black, 0, height * i+10, 30, height);	
					
					string[] sss = ToStr(min + step * i);
					if (sss.Length == 2)
						bg.DrawString(sss[0] + "E" + sss[1], new Font("宋体", 10), Brushes.Black, 32, height * i + 5);
					else
						bg.DrawString(sss[0], new Font("宋体", 10), Brushes.Black, 32 , height * i + 5);
					
				}
				string[] ss1 = ToStr(max);
				if (ss1.Length==2)
					bg.DrawString(ss1[0] + "E" + ss1[1], new Font("宋体", 10), Brushes.Black, 32, height * count + 5);
				else
					bg.DrawString(ss1[0], new Font("宋体", 10), Brushes.Black, 32, height * count + 5);
				
				
//				double inc = (max - min) / 500;
//				Color color;
//				for (int i = 0; i < 500; i++) {
//					color = MatrixFuncs.ToColor6(min, max, i * inc + min);
//					Pen pen = new Pen(color);
//					int yy = 500 - i - 1;
//					bg.DrawLine(pen, 0, yy, 30, yy);        		
//				}
				Pen linePen = new Pen(Color.Black, 1);
//				bg.DrawLine(linePen, 0, 255, 30, 255);
				//bg.DrawRectangle(linePen, 0, 0, 30, 500);
            	
			}
			g.DrawImage(colorbarImage, x, y);
//			string[] sss = ToStr(MinValue);
//			if (sss.Length == 2) {
//				g.DrawString("x10^" + sss[1], new Font("Times New Rome", 10), Brushes.Black, x + 37, 500 + y - 15);
//			}
//			g.DrawString(sss[0], new Font("Times New Rome", 10), Brushes.Black, x + 32, 500 + y);        		
//        	
//            
//			sss = ToStr(MaxValue);      
//			if (sss.Length == 2) {
//				g.DrawString("x10^" + sss[1], new Font("Times New Rome", 10), Brushes.Black, x + 37, y - 5);
//			}
//			g.DrawString(sss[0], new Font("Times New Rome", 10), Brushes.Black, x + 32, y + 10);
//			sss = ToStr((MaxValue + MinValue) / 2);
//			if (sss.Length == 2) {
//				g.DrawString("x10^" + sss[1], new Font("Times New Rome", 10), Brushes.Black, x + 37, y + 255 - 15);
//			}
//			g.DrawString(sss[0], new Font("Times New Rome", 10), Brushes.Black, x + 32, y + 255);
        	
		}
		/// <summary>
		/// 生成黑白灰度图像
		/// </summary>
		/// <returns></returns>
		public Bitmap CreateBitmap()
		{
			Bitmap bitmap = MatrixFuncs.BitmapFromMatrix(this.Values);
			this.theBitmap = bitmap;
			return bitmap;
		}
		/// <summary>
		/// 生成双色图像
		/// </summary>
		/// <returns></returns>
		public Bitmap CreateBitmap(Color color1, Color color2)
		{
			Bitmap bitmap = MatrixFuncs.BitmapFromMatrix2(this.Values, color1, color2);
			this.theBitmap = bitmap;
			return bitmap;
		}
		public Bitmap CreateBitmap(Color color1, Color color2, Color color3)
		{
			Bitmap bitmap = MatrixFuncs.BitmapFromMatrix3(this.Values, color1, color2, color3);
			this.theBitmap = bitmap;
			return bitmap;
		}
		void SetGradientColors(int nCount, Color clrFirst, Color clrNext)
		{
		}
		void SetRange(int range, Color m_clrStart, Color m_clrEnd)
		{
		}

		public override string ToString()
		{
			return this.FileName;
		}

		/// <summary>
		/// 绝对数直方图
		/// </summary>
		SortedList<double, int> AbsoluteHistgram = new SortedList<double, int>();
		/// <summary>
		/// 比例直方图
		/// </summary>
		SortedList<double, double> PercentageHistgram = new SortedList<double, double>();
		/// <summary>
		/// 栅格总行数
		/// </summary>
		public int colCount {
			get {
				return this.Values.GetLength(1);
			}
		}
		public int rowCount {
			get {
				return this.Values.GetLength(0);
			}
		}
		private int rCount;
		private int cCount;
		/// <summary>
		/// 分辨率(米/栅格长宽)
		/// </summary>
		public double resolution;
		/// <summary>
		/// 栅格最左上角栅格的UTM X坐标值(米),-1表示未设置
		/// </summary>
		public double DownLeft_X = -1;
		/// <summary>
		/// 栅格最左上角栅格的UTM Y坐标值(米),-1表示未设置
		/// </summary>
		public double DownLeft_Y = -1;
		public MapExtent Extent {
			get {
				MapExtent extent = new MapExtent();
				extent.xmin = DownLeft_X;
				extent.ymin = DownLeft_Y;
				extent.xmax = DownLeft_X + this.colCount * this.resolution;
				extent.ymax = DownLeft_Y + this.rowCount * this.resolution;
				return extent;
			}
		}
		/// <summary>
		/// 空数据值
		/// </summary>
		public double nodata = -9999;
		public double[,] Values;
		//存放值的矩阵
		public double this[int rowIndex, int colIndex] {
			set {
				this.Values[rowIndex, colIndex] = value;
			}
			get {
				return this.Values[rowIndex, colIndex];
			}
		}
		public string FileName;

		public double MaxValue;
		//最大像元值
		public double MinValue;
		//最小像元值
		public Bitmap theBitmap;
        
	};
}
